package com.gopay.common.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.FileSystemResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
/**
 * 文件工具类
 *
 * @author wangdong - 2016-04-20
 */
public class GsrtFileUtil {
    /**
     * Get the canonical file path according to the relative or classpath file
     * path.
     * 
     * @param filePath
     *            relative or classpath file path.
     * @return canonical file path, or return <code>filePath</code> if
     *         designated file does not exist or can not be read due to
     *         permission.
     */
    public static String getCanonicalFilePath(String filePath) {
        try {
            ResourceLoader resourceLoader = new DefaultResourceLoader();
            Resource resource = resourceLoader.getResource(filePath);
            File file = null;
            if (resource.exists()) {
                file = resource.getFile();
            } else {
                resourceLoader = new FileSystemResourceLoader();
                resource = resourceLoader.getResource(filePath);
                if (resource.exists()) {
                    file = resource.getFile();
                } else {
                    return filePath;
                }
            }
            if (file != null && file.exists() && file.isFile()) {
                String absFilePath = file.getCanonicalPath();
                return absFilePath;
            } else {
                return filePath;
            }
        } catch (Exception e) {
            return filePath;
        }
    }

    private static Logger logger = Logger.getLogger(GsrtFileUtil.class);

    /**
     * 默认缓冲区大小 1M
     */
    private static final int BUFF_SIZE = 1024 * 1024;

    /**
     * 文件路径分隔符
     */
    public static final String FILE_SEPARATOR = File.separator;

    private static Map<String, ReentrantLock> locks = Collections
            .synchronizedMap(new HashMap<String, ReentrantLock>());

    /**
     * @throws IOException
     * @throws FileNotFoundException
     *
     * @return ArrayList<String> 分行数据字符串集合
     * @param filePath
     * @param charsetName
     */
    public static ArrayList<String> readFile(String filePath,String charsetName) throws IOException {
        FileInputStream file = null;
        InputStreamReader inputStreamReader = null;
        BufferedReader br = null;
        try {
            ArrayList<String> list = new ArrayList<String>();
            file = new FileInputStream(filePath);
            String temp = "";
            inputStreamReader = new InputStreamReader(file,charsetName);
            br = new BufferedReader(inputStreamReader);
            while (temp != null) {
                temp = br.readLine();
                if (temp != null) {
                    list.add(temp);
                }
            }
            return list;
        }
        catch(IOException ex) {
            throw ex;
        }
        finally {
            if(br != null) {
                br.close();
            }
            if(inputStreamReader != null) {
                inputStreamReader.close();
            }
            if(file != null) {
                file.close();
            }
        }
    }

    /**
     * 创建文件
     * @param fileName
     * @return
     */
    public static boolean createFile(File fileName)throws Exception{
        boolean flag=false;
        try{
            if(!fileName.exists()){
                fileName.createNewFile();
                flag=true;
            }
        }catch(Exception e){
            e.printStackTrace();
        }
        return true;
    }

    /**
     * 读TXT文件内容
     * @param fileName
     * @return
     */
    public static String readTxtFile(File fileName)throws Exception{
        String result=null;
        FileReader fileReader=null;
        BufferedReader bufferedReader=null;
        try{
            fileReader=new FileReader(fileName);
            bufferedReader=new BufferedReader(fileReader);
            try{
                String read=null;
                while((read=bufferedReader.readLine())!=null){
                    result=result+read+"\r\n";
                }
            }catch(Exception e){
                e.printStackTrace();
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            if(bufferedReader!=null){
                bufferedReader.close();
            }
            if(fileReader!=null){
                fileReader.close();
            }
        }
        System.out.println("读取出来的文件内容是："+"\r\n"+result);
        return result;
    }

    public static boolean writeTxtFile(String content,File fileName)throws Exception{
//        RandomAccessFile mm=null;
        boolean flag=false;
        FileOutputStream o=null;
        try {
            o = new FileOutputStream(fileName);
            o.write(content.getBytes("GBK"));
            o.close();
//           mm=new RandomAccessFile(fileName,"rw");
//           mm.writeBytes(content);
            flag=true;
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
//        finally{
//            if(mm!=null){
//                mm.close();
//            }
//        }
        return flag;
    }



    public static void contentToTxt(String filePath, String content) {
        String str = new String(); //原有txt内容
        String s1 = new String();//内容更新
        try {
            File f = new File(filePath);
            if (f.exists()) {
                System.out.print("文件存在");
            } else {
                System.out.print("文件不存在");
                f.createNewFile();// 不存在则创建
            }
            BufferedReader input = new BufferedReader(new FileReader(f));

            while ((str = input.readLine()) != null) {
                s1 += str + "\n";
            }
            System.out.println(s1);
            input.close();
            s1 += content;

            BufferedWriter output = new BufferedWriter(new FileWriter(f));
            output.write(s1);
            output.close();
        } catch (Exception e) {
            e.printStackTrace();

        }
    }

    /**
     * 读取文件
     *
     * @param fileName
     * @return
     * @throws IOException
     */
    public static List<String[]> readByLine(String fileName,
                                            String charsetName) throws IOException {
        FileInputStream file = new FileInputStream(fileName);
        BufferedReader br = null;
        InputStreamReader inputStreamReader = null;
        ArrayList<String[]> list = new ArrayList<String[]>();
        String[] strArr = null;
        String temp = "";
        try {
            inputStreamReader = new InputStreamReader(file, charsetName);
            br = new BufferedReader(inputStreamReader);
            while (temp != null) {
                temp = br.readLine();
                if (temp != null) {
                    strArr = StringUtils.splitPreserveAllTokens(temp, "|");
                    list.add(strArr);
                }
            }
        } catch (FileNotFoundException e) {
            throw e;
        } catch (IOException e) {
            throw e;
        } finally {
            if (null != br) {
                br.close();
            }
            if (null != inputStreamReader) {
                inputStreamReader.close();
            }
            if (null != file) {
                file = null;
            }
        }
        return list;
    }

    /**
     * 移动单个文件
     *
     * @param oldFile
     *            String 原文件路径 如：c:/fqf.txt
     * @param newPath
     *            String 复制后路径 如：f:/fqf.txt
     */
    @SuppressWarnings("unused")
    private void moveFile(File oldFile, String newPath) throws Exception{
        // logger.error("备份文件目录:"+newPath);
        InputStream inStream = null;
        FileOutputStream fs = null;
        try {
            int bytesum = 0;
            int byteread = 0;
            if (oldFile.exists()) {
                inStream = new FileInputStream(oldFile);
                fs = new FileOutputStream(newPath);
                byte[] buffer = new byte[512];
                while ((byteread = inStream.read(buffer)) != -1) {
                    bytesum += byteread;
                    fs.write(buffer, 0, byteread);
                }
                oldFile.delete();
            }
        } catch (Exception e) {
            throw e;
        }
        finally {
            if(fs != null) {
                fs.close();
            }
            if(inStream != null) {
                inStream.close();
            }
        }
    }

    /**
     * 记录内容信息到指定路径(内容追加)
     *
     * @param path
     *            路径
     * @param content
     *            内容
     * @return 成功返回true
     */
    public static boolean write(String path, String content) {
        synchronized (locks) {
            ReentrantLock lock = locks.get(path);
            if (lock == null) {
                lock = new ReentrantLock();
                locks.put(path, lock);
            }
            try {
                lock.lock();
                FileWriter fw = null;
                try {
                    fw = new FileWriter(path, true);
                    fw.write(content + "\r\n");
                    fw.flush();
                } catch (IOException e) {
                    logger.error("File Write Exception：", e);
                } finally {
                    try {
                        if (null != fw) {
                            fw.close();
                        }
                    } catch (IOException e) {
                        logger.error("Close FileWriter Exception：", e);
                    }
                }
                if (lock.getQueueLength() == 0) {
                    locks.remove(path);
                }
            } finally {
                lock.unlock();
            }
        }
        return true;
    }

    /**
     * 压缩文件
     * @param fileFullPathName ：c:/test.txt, zipFileFullPathName: c:/zip/test.zip
     */
    public void zipFile(String fileFullPathName, String zipFileFullPathName){
        ZipOutputStream out = null;
        FileInputStream in = null;
        try {
            out = new ZipOutputStream(new FileOutputStream(fileFullPathName));
            in = new FileInputStream(zipFileFullPathName);

            byte[] buf = new byte[1024];
            int len;
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
            out.finish();

        }
        catch (IOException e) {
            e.printStackTrace();
        }
        finally {
            try {
                if(out != null) {
                    out.close();
                }
                if(in != null) {
                    in.close();
                }
            }
            catch(Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    /**
     * 批量压缩文件
     * @param files 要压缩的文件列表
     * @param zipFile 生成的压缩文件
     * @throws IOException
     */
    public void zipFiles(Collection<File> files, File zipFile) throws IOException{
        ZipOutputStream out = null;
        FileOutputStream zipOut = null;
        BufferedOutputStream bufferOut = null;
        try {
            if (files != null){
                zipOut = new FileOutputStream(zipFile);
                bufferOut = new BufferedOutputStream(zipOut, BUFF_SIZE);
                out = new ZipOutputStream(bufferOut);
                for(File file : files){
                    zipFile(file, out, "");
                }
            }
        }
        catch(IOException ex) {
            throw ex;
        }
        finally {
            if(zipOut != null) {
                zipOut.close();
            }
            if(bufferOut != null) {
                bufferOut.close();
            }
            if(out != null) {
                out.close();
            }
        }
    }

    /**
     * 将文件写入压缩包
     * @param resFile 要压缩的文件
     * @param zipOut 文件压缩输出流
     * @param rootPath 文件根路径
     * @throws IOException
     */
    public static void zipFile(File resFile, ZipOutputStream zipOut, String rootPath) throws IOException{
        BufferedInputStream in = null;
        FileInputStream fin = null;
        try {
            rootPath = rootPath
                    + (rootPath.trim().length() == 0 ? "" : File.separator)
                    + resFile.getName();

            if (resFile.isDirectory()){
                File[] fileList = resFile.listFiles();
                for(File file : fileList){
                    zipFile(file, zipOut, rootPath);
                }
            } else {
                byte buffer[] = new byte[BUFF_SIZE];
                fin = new FileInputStream(resFile);
                in = new BufferedInputStream(fin, BUFF_SIZE);
                zipOut.putNextEntry(new ZipEntry(rootPath));
                int realLength;
                while((realLength = in.read(buffer)) != -1){
                    zipOut.write(buffer, 0, realLength);
                }
                zipOut.flush();
                zipOut.closeEntry();
            }
        }
        catch(IOException ex) {
            throw ex;
        }
        finally {
            if(fin != null) {
                fin.close();
            }
            if(in != null) {
                in.close();
            }
        }
    }

    /**
     * 解压缩指定的文件
     */
    public void unCompressFile(String zipFileFullPathName, String fileFullPathName){
        ZipInputStream in = null;
        FileOutputStream out = null;
        try {
            in = new ZipInputStream(new FileInputStream(zipFileFullPathName));
            out = new FileOutputStream(fileFullPathName);

            byte[] buf = new byte[1024];
            int len;
            while ((len = in.read(buf)) > 0) {
                logger.info(buf);
                logger.info(len);
                out.write(buf, 0, len);
            }
        }
        catch (IOException e) {
            e.printStackTrace();
        }
        finally {
            try {
                if(out != null) {
                    out.close();
                }
                if(in != null) {
                    in.close();
                }
            }
            catch(Exception ex) {
                ex.printStackTrace();
            }
        }
    }
    /**
     * 备份指定的文件
     * @param fileFullPathName
     * @param bakFileFullPathName
     */
    public File backupFile(String fileFullPathName, String bakFileFullPathName){
        File backupFile = new File(bakFileFullPathName);
        new File(fileFullPathName).renameTo(backupFile);
        return backupFile;
    }

    /**
     * 删除单个文件
     * @param   fileName    被删除文件的文件名
     * @return 单个文件删除成功返回true,否则返回false
     */
    public static boolean deleteFile(String fileName){
        File file = new File(fileName);
        if(file.isFile() && file.exists()){
            file.delete();
            logger.info("删除单个文件"+fileName+"成功！");
            return true;
        }else{
            logger.error("删除单个文件"+fileName+"失败！");
            return false;
        }
    }

    /**
     * 删除目录（文件夹）以及目录下的文件
     * @param   dir 被删除目录的文件路径
     * @return  目录删除成功返回true,否则返回false
     */
    public static boolean deleteDirectory(String dir){
        //如果dir不以文件分隔符结尾，自动添加文件分隔符
        if(!dir.endsWith(File.separator)){
            dir = dir+File.separator;
        }
        File dirFile = new File(dir);
        //如果dir对应的文件不存在，或者不是一个目录，则退出
        if(!dirFile.exists() || !dirFile.isDirectory()){
            logger.error("删除目录失败"+dir+"目录不存在！");
            return false;
        }
        boolean flag = true;
        //删除文件夹下的所有文件(包括子目录)
        File[] files = dirFile.listFiles();
        for(int i=0;i<files.length;i++){
            //删除子文件
            if(files[i].isFile()){
                flag = deleteFile(files[i].getAbsolutePath());
                if(!flag){
                    break;
                }
            }
            //删除子目录
            else{
                flag = deleteDirectory(files[i].getAbsolutePath());
                if(!flag){
                    break;
                }
            }
        }

        if(!flag){
            logger.error("删除目录失败");
            return false;
        }

        //删除当前目录
        if(dirFile.delete()){
            logger.info("删除目录"+dir+"成功！");
            return true;
        }else{
            logger.error("删除目录"+dir+"失败！");
            return false;
        }
    }

    /**
     * 解压zip或rar文件，原样解压
     * @param zipFilename
     * @param outputDirectory
     * @throws IOException
     */
    public static void unzip(String zipFilename, String outputDirectory) throws IOException{
        File outdir = new File(outputDirectory);
        ZipInputStream zin = new ZipInputStream(new FileInputStream(new File(zipFilename)));
        ZipEntry entry;
        String name, dir;
        while((entry = zin.getNextEntry()) != null){
            name = entry.getName();
            if (entry.isDirectory()){
                mkdirs(outdir, name);
                continue;
            }

            dir = dirpart(name);
            if (dir != null){
                mkdirs(outdir, dir);
            }

            extractFile(zin, outdir, name);
        }

        zin.close();
    }

    /**
     * 解压zip或者rar包的内容到指定的目录下，可以处理其文件夹下包含子文件夹的情况
     * @param zipFilename 要解压的zip或者rar包文件
     * @param outputDirectory 解压后存放的目录
     */
    public static List<String> unzipToSameDir(String zipFilename, String outputDirectory)
            throws IOException {
        List<String> list = new ArrayList<String>();
        File outFile = new File(outputDirectory);
        if (!outFile.exists()) {
            outFile.mkdirs();
        }
        int BUFFEREDSIZE = 1024;

        ZipFile zipFile = new ZipFile(zipFilename);
        Enumeration en = zipFile.entries();
        ZipEntry zipEntry = null;
        while (en.hasMoreElements()) {
            zipEntry = (ZipEntry) en.nextElement();
            if (!zipEntry.isDirectory()) {// unzip file
                String[] arrFolderName = StringUtils.split(zipEntry.getName(),"/");
                String outFlieName = arrFolderName[arrFolderName.length-1];
                list.add(outFlieName);
                String strFilePath = outFile.getPath() + File.separator
                        + outFlieName;
                File f = new File(strFilePath);
                f.createNewFile();
                InputStream in = null;
                FileOutputStream out = null;
                try {
                    in = zipFile.getInputStream(zipEntry);
                    out =  new FileOutputStream(f);
                    int c;
                    byte[] by = new byte[BUFFEREDSIZE];
                    while ((c = in.read(by)) != -1) {
                        out.write(by, 0, c);
                    }
                    out.flush();
                } catch (IOException e) {
                    throw e;
                } finally {
                    if(out != null) {
                        out.close();
                    }
                    if(in != null) {
                        in.close();
                    }
                }
            }
        }
        return list;
    }

    /**
     * 解压gs文件
     * @param gsFilename
     * @param outputFilename
     * @throws IOException
     */
    public static void doUncompressFile(String gsFilename, String outputFilename) throws IOException{
        int BUFFEREDSIZE = 1024;

        int count;
        byte data[] = new byte[BUFFEREDSIZE];
        GZIPInputStream gis = null;
        FileInputStream fin = null;
        FileOutputStream os = null;
        try{
            fin = new FileInputStream(gsFilename);
            gis = new GZIPInputStream(fin);
            os = new FileOutputStream(new File(outputFilename));
            while((count = gis.read(data, 0, BUFFEREDSIZE)) != -1){
                os.write(data, 0, count);
            }

            os.flush();
        }catch(IOException e){
            throw e;
        }finally{
            if(os != null) {
                os.close();
            }
            if(fin != null) {
                fin.close();
            }
            if(gis != null) {
                gis.close();
            }
        }
    }

    /**
     * @Title: isExists
     * @author Eric bjwdong@cn.ibm.com
     * @Description: 判断文件是否存在
     * @param @param filePath
     * @param @return
     * @return boolean
     * @throws
     */
    public static boolean isExists(String filePath){
        File file = new File(filePath);
        if(file.isFile() && file.exists()){
            return true;
        }
        return false;
    }
    /**
     * @param path
     *            文件路径
     * @param suffix
     *            后缀名, 为空则表示所有文件
     * @param isdepth
     *            是否遍历子目录
     * @return list
     */
    public static List<String> getListFiles(String path, String suffix,
                                            boolean isdepth) {
        List<String> lstFileNames = new ArrayList<String>();
        File file = new File(path);
        return listFile(lstFileNames, file, suffix, isdepth);
    }

    public static List<String> getListFiles(String path, String suffix, String startString,
                                            boolean isdepth) {
        List<String> lstFileNames = new ArrayList<String>();
        File file = new File(path);
        return listFile(lstFileNames, file, startString, suffix, isdepth);
    }

    private static List<String> listFile(List<String> lstFileNames, File f,
                                         String suffix, boolean isdepth) {
        // 若是目录, 采用递归的方法遍历子目录
        if (f.isDirectory()) {
            File[] t = f.listFiles();

            for (int i = 0; i < t.length; i++) {
                if (isdepth || t[i].isFile()) {
                    listFile(lstFileNames, t[i], suffix, isdepth);
                }
            }
        } else {
            String filePath = f.getAbsolutePath();
            if (!suffix.equals("")) {
                int begIndex = filePath.lastIndexOf("."); // 最后一个.(即后缀名前面的.)的索引
                String tempsuffix = "";

                if (begIndex != -1) {
                    tempsuffix = filePath.substring(begIndex + 1, filePath
                            .length());
                    if (tempsuffix.equals(suffix)) {
                        lstFileNames.add(filePath);
                    }
                }
            } else {
                lstFileNames.add(filePath);
            }
        }
        return lstFileNames;
    }

    private static List<String> listFile(List<String> lstFileNames, File f, String startString,
                                         String suffix, boolean isdepth) {
        // 若是目录, 采用递归的方法遍历子目录
        if (f.isDirectory()) {
            File[] t = f.listFiles();

            for (int i = 0; i < t.length; i++) {
                if (isdepth || t[i].isFile()) {
                    listFile(lstFileNames, t[i], startString, suffix, isdepth);
                }
            }
        } else {
            String filePath = f.getAbsolutePath();
            boolean equalsSuffix = false;
            if (!suffix.equals("")) {
                int begIndex = filePath.lastIndexOf("."); // 最后一个.(即后缀名前面的.)的索引
                String tempsuffix = "";

                if (begIndex != -1) {
                    tempsuffix = filePath.substring(begIndex + 1, filePath
                            .length());
                    if (tempsuffix.equals(suffix)) {
                        //lstFileNames.add(filePath);
                        equalsSuffix = true;
                    }
                }
            } else {
                //lstFileNames.add(filePath);
                equalsSuffix = true;
            }

            boolean equalsStartString = false;
            if(f.getName().indexOf(startString) == 0) {
                equalsStartString = true;
            }

            if(equalsSuffix && equalsStartString) {
                lstFileNames.add(filePath);
            }

        }
        return lstFileNames;
    }

    private static void extractFile(ZipInputStream in, File outdir, String name) throws IOException {
        byte[] buffer = new byte[BUFF_SIZE];
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(new File(outdir, name)));
        int count = -1;
        while((count = in.read(buffer)) != -1){
            out.write(buffer, 0, count);
        }

        out.close();
    }

    private static void mkdirs(File outdir, String path){
        File d = new File(outdir, path);
        if (!d.exists()){
            d.mkdirs();
        }
    }

    private static String dirpart(String name){
        int s = name.lastIndexOf(File.separatorChar);
        return s == -1 ? null : name.substring(0, s);
    }

    public static void main(String[] args){
        List<String> list = GsrtFileUtil.getListFiles("C:\\Users\\IBM_ADMIN", "sql",false);
        for(String name:list){
            System.out.println("name="+name+" "+name.length()+"  "+File.separator+"  "+name.substring(name.lastIndexOf(File.separator)+1));
        }
    }
}
